package main

import "fmt"

/*
1、map是一种内置的数据结构是key(索引)和value的无序集合，用于存储键值对，map是引用类型，必须初始化才能使用，Go语言中的map有如下特点
内置数据结构：map是Go语言内置的数据结构，它是一种无序的键值对集合，其中键是唯一的。Go语言在语言级别支持map， 使用方便。
快速查找：map提供了非常快速的查找、插入和删除操作，这些操作的平均时间复杂度为O(1)。这使得map非常适合用于需要快速访问数据的场景。
动态性：map是动态的，可以在运行时动态地增加或删除键值对，而不需要预先声明大小。
键的多样性：Map的键可以是任何可比较的类型，例如整数、字符串等。这为存储和检索各种类型的数据提供了灵活性。
非并发安全：标准的Map在Go中并不是线程安全的。如果需要在多个goroutine中并发访问Map，需要使用sync包中的Mutex或RWMutex来保证并发安全，或者使用并发安全的数据结构，如sync.Map。
应用场景：Map在Go中被广泛应用于各种场景，如数据库查询结果的存储、配置项的读取、缓存的实现等。
*/

func main() {
	/*
		一、map的声明
		var 名称 map[键的类型]值的类型
		var map_name map[key_type]value_type
	*/
	var map1 map[string]string
	//如上只是声明了map没有初始化，使用Map时，如果没有初始化（即值为nil），直接赋值会导致运行时错误。
	// map1["go"] = "go开发工程师"    像这样没有初始化就直接赋值会报错
	if map1 == nil {
		fmt.Println(map1) //空的map[]
	}

	/*
		二、map的初始化
	*/
	// 1、var map_name[key_type]value_type{}方式初始化
	var map2 = map[string]string{} //该map就已经被初始化了，无论{}里面是否有东西
	var map3 = map[string]string{
		"jiang": "18",
		"li":    "19",
	}
	//需注意{}方式初始化最后的一个键值需要","结尾
	map2["java"] = "java工程师"
	fmt.Printf("map1=%v\nmap2=%v\n", map2, map3)

	//2、make(map[key_type]value_type, [cap])方式初始化
	//其中cap表示map的容量，该参数虽然不是必须的，但是我们应该在初始化map的时候就为其指定一个合适的容量，并且获取map的容量使用len()
	map4 := make(map[string]string, 3)
	map4["jiang"] = "18"

	/*
		三、map基本操作：增、删、改、查
	*/
	map5 := make(map[string]string, 3)
	// 增（Insert）： 向Map中添加新的键值对； 如果key已存在，则更新value
	map5["orange"] = "15"
	map5["apple"] = "16"
	map5["banana"] = "17"
	// 删（Delete）： 从Map中删除键值对； 如果key不存在，delete函数不会执行任何操作。
	delete(map5, "apple")

	// 改（Update）： 更新Map中的键值对; 如果key已经存在，这将替换原来的值。如果key不存在，这将添加一个新的键值对
	map5["banana"] = "20"

	// 查（Lookup）：查找Map中的键对应的值；
	value, exists := map5["banana"] // 这里value是与键关联的值，exists是一个布尔值，如果键存在于Map中，则为true；如果键不存在，则为false，并且value将是类型的零值。
	value2 := map5["banana"]        // 如果你只关心值，可以忽略第二个返回值
	fmt.Println(value, exists)
	fmt.Printf("value=%v\n", value2)

	/*
		四、map的遍历
	*/
	map6 := map[string]string{
		"go":   "go开发",
		"java": "java开发",
		"vue":  "vue开发",
	}
	fmt.Println("*****************************map的遍历*****************************")
	for key, value := range map6 {
		fmt.Println(key, value)
	}
	fmt.Println("*****************************map的遍历*****************************")
	for key := range map6 {
		fmt.Println(key, map6[key])
	}
	// 由于map是无序的，每次的遍历顺序不保证一致
	/*
		五、map判断某个元素是否存在
		采用了map查找的方式
	*/
	map7 := map[string]string{
		"go":   "go开发",
		"java": "java开发",
		"vue":  "vue开发",
	}
	//这里value3是与键关联的值，exists2是一个布尔值，如果键存在于Map中，则为true，value3为实际值
	//如果键不存在，则为false，并且value将是类型的零值。
	value3, exists2 := map7["python"]
	if exists2 {
		fmt.Println("python in ma7")
	} else {
		fmt.Println("python not in ma7")
	}
	fmt.Println(value3)

	//上面类型的if判断在go中还有更加简洁的写法
	// 为true时的写法
	if _, exists2 := map7["python"]; exists2 {
		fmt.Println("python in ma7")
	}
	//为false的写法
	if _, exists2 := map7["python"]; !exists2 {
		fmt.Println("python not in ma7")
	}
}
